﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace System.Threading.Tasks
{
    /// <summary>
    /// Supports asynchronous initialization of a state variable without blocking in contructor.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <example><code>
    /// <![CDATA[
    /// var target = new AsyncLazy<string>(() =>
    /// {
    ///     Thread.Sleep(300);
    ///     return expectedString;
    /// });
    /// var result = await target;
    /// ]]></code>
    /// </example>
    public class AsyncLazy<T> : Lazy<Task<T>>
    {
        /// <summary>
        /// CTOR: Calls the function asynchronously in the background to createT.
        /// </summary>
        /// <param name="valueFactory">factory for creating the value</param>
        public AsyncLazy(Func<T> valueFactory) :
            base(() => Task.Factory.StartNew(valueFactory)) { }

        /// <summary>
        /// CTOR: Uses a task factory called asynchronously in the background to create T.
        /// </summary>
        /// <param name="taskFactory">factory for creating the value</param>
        public AsyncLazy(Func<Task<T>> taskFactory) :
            base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap()) { }

        /// <summary>
        /// <see cref="Task.GetAwaiter"/>
        /// </summary>
        /// <returns><see cref="Task.GetAwaiter"/></returns>
        public TaskAwaiter<T> GetAwaiter()
        {
            return base.Value.GetAwaiter();
        }
    }
}
